/**
 * Copyright (c) 2006-2012 Las Venturas Playground, LVP Mineground
 *
 * This program is free software: you can redistribute it and/or modify it under the terms of the
 * GNU General Public License as published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
 * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package mineground.core;

import mineground.util.Log;

/**
 * Since Las Venturas Mineground is completely based on sending events around, spreading load
 * across multiple threads will be done by creating one or more workers and separating functionality
 * through the Message Loop. Each WorkerThread is owned by the Mineground class and represents
 * one of the values of the MessageLoopThread enum.
 * 
 * Workers will poll for incoming tasks on the several threads and execute these accordingly. A
 * predefined maximum number of tasks will be executed per iteration, making sure that the thread
 * can pause frequently enough to not become a CPU hog.
 */
public class WorkerThread extends Thread {
    /**
     * What is the interval at which a worker thread should process tasks queued in the message
     * loop? Low numbers increase responsiveness, but may also increase load on the server itself.
     * Finding the ideal number here should be done by the lead developers.
     */
    private final static int WorkerThreadLoopIterationInterval = 4;
    
    /**
     * We need the Message Loop to be actually able to poll for incoming tasks to run on our end.
     * Furthermore, this thread needs to register and remove itself depending on its state. Since
     * we want to access some non-default API methods, store the implementation.
     */
    private MessageLoopImpl mMessageLoop;
    
    /**
     * Worker threads are incredibly dumb - they don't care about what they'll do, as they will
     * only work on the code that's been passed on to them. 
     */
    private MessageLoopThread mThreadId;
    
    /**
     * Has a shutdown been requested for this thread? The request itself will originate from the
     * Server Thread, while it'll be handled by us directly.
     */
    private Boolean mRequestedShutdown;
    
    /**
     * Initialize a Worker Thread by creating a named thread, setting the required local variables
     * (which are one-time-write, so we don't have to worry about thread safety when using them in
     * the future) and start running it immediately.
     */
    public WorkerThread(MessageLoop messageLoop, MessageLoopThread threadId, String threadName) {
        super(threadName);
        
        mMessageLoop = (MessageLoopImpl) messageLoop;
        mThreadId = threadId;
        mRequestedShutdown = false;
        
        start();
    }
    
    /**
     * Actually running the Worker Thread itself involves a few easy tasks. Firstly, we have to make
     * sure that it's availability is properly announced against the Message Loop. Then iterate
     * in infinity until a shutdown request has been received. Invoke the Message Loop's processor
     * and sleep for a number of milliseconds, preventing unneccesary CPU hug.
     */
    public void run() {
        mMessageLoop.updateThreadAvailability(mThreadId, true);
        Log.notice("The WorkerThread '%s' has started.", this.getName());
        
        // Poll for incoming tasks until the thread has received a shut-down notice. We'll want to
        // check for threads at least once, even if shutdown has been requested before we've started.
        do {
            mMessageLoop.run(mThreadId);
            
            try {
                Thread.sleep(WorkerThreadLoopIterationInterval);
            } catch (InterruptedException e) { }
        } while (!shouldShutdown());
        
        // We're done. Output a notice about this, and unregister ourselves from the Message Loop.
        Log.notice("The WorkerThread '%s' has been shut down.", this.getName());
        mMessageLoop.updateThreadAvailability(mThreadId, false);
    }
    
    /**
     * Request this thread to be shut down. The requestedShutdown flag in this class will be set to
     * true, causing the worker to stop requesting tasks from the MessageLoop on the next iteration.
     * Keep in mind that we have no knowledge of when it will actually be shut down.
     */
    public void requestShutdown() {
        synchronized (mRequestedShutdown) {
            mRequestedShutdown = true;
        }
    }
    
    /**
     * Determine whether this working thread should shut down. This will be called from inside the
     * run() method as the condition for the loop we're running into.
     */
    private synchronized boolean shouldShutdown() {
        return mRequestedShutdown;
    }
}
